package service

import (
	"errors"
	"fmt"
	"net"
	"strconv"
	"time"

	"cashway.com/cis/assistant/model"
	"cashway.com/cis/assistant/utils"
)

func TcpRequest(params *model.TcpRequestParams) ([]byte, error) {
	if params.Address == "" {
		return nil, errors.New("参数 'address' 不能为空")
	}

	if params.RespCheckLength <= 0 {
		return nil, errors.New("参数 'respCheckLength' 不能小于或等于 '0'")
	}

	// 自动计算请求数据长度
	if params.SendDataLength == "" {
		// 若计算请求数据长度为 0，则取响应数据校验长度
		if params.ReqCalcLength <= 0 {
			params.ReqCalcLength = params.RespCheckLength
		}
		params.SendDataLength = utils.FormatStringLength(params.Data, params.RespCheckLength)
	}

	params.Data = params.SendDataLength + params.Data

	conn, err := net.Dial("tcp", params.Address)
	if err != nil {
		return nil, err
	}
	defer conn.Close()

	_, err = conn.Write([]byte(params.Data))
	if err != nil {
		return nil, err
	}

	// 计算超时时间
	var deadline time.Time
	if params.Timeout > 0 {
		timer, err := time.ParseDuration(fmt.Sprintf("%ds", params.Timeout))
		if err != nil {
			return nil, err
		}
		deadline = time.Now().Add(timer)
	}

	buf := make([]byte, 1024)
	resp := make([]byte, 0)
	respLen := 0
	getRespLenFlag := false
	for {
		if params.Timeout > 0 && time.Now().After(deadline) {
			return nil, errors.New("远程端响应超时")
		}

		n, err := conn.Read(buf)
		if err != nil {
			return nil, errors.New("接收远程端响应数据失败")
		}

		if n > 0 {
			resp = append(resp, buf[:n]...)
		}

		// 获取报文头长度
		if !getRespLenFlag && len(resp) >= params.RespCheckLength {
			respLen, err = strconv.Atoi(string(resp[:params.RespCheckLength]))
			if err != nil {
				return nil, errors.New("获取 Byte 报文头长度失败")
			}
			getRespLenFlag = true
		}

		// 响应数据
		if getRespLenFlag && len(resp) >= respLen+params.RespCheckLength {
			return resp[params.RespCheckLength:], nil
		}
	}
}
